package com.sisgh.jefdv1.core.java.format;

import com.sisgh.jefdv1.core.entity.Entity;
import com.sisgh.jefdv1.core.entity.field.Field;
import com.sisgh.jefdv1.core.java.keyword.imports.impl.Extend;
import com.sisgh.jefdv1.exception.java.JavaFormatException;
import com.sisgh.jefdv1.core.java.keyword.imports.Import;
import com.sisgh.jefdv1.core.java.keyword.imports.impl.Annotation;
import com.sisgh.jefdv1.core.java.keyword.pack.Package;
import com.sisgh.jefdv1.lang.FormatStringBuilder;
import com.sisgh.jefdv1.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * Java格式处理器
 */
public class JavaFormatProcessor {
    /**
     * Java StringBuilder
     * 负责添加对应的字符串
     */
    private static class JavaStringBuilder {
        /**
         * 关键字符串
         */
        private static final String START_PREFIX = "public class";
        private static final String BRACE_START = "{";
        private static final String BRACE_END = "}";
        private static final String EXTENDS = "extends";
        private static final String END_IDENTIFIER = ";";

        /**
         * 对应结构
         */
        private final FormatStringBuilder pack;
        private final FormatStringBuilder imports;
        private final FormatStringBuilder annotations;
        private final FormatStringBuilder entity;

        // 是否有 @Data 注解
        private boolean isData;

        private JavaStringBuilder() {
            pack = new FormatStringBuilder(END_IDENTIFIER);
            imports = new FormatStringBuilder(END_IDENTIFIER);
            annotations = new FormatStringBuilder(END_IDENTIFIER);
            entity = new FormatStringBuilder(END_IDENTIFIER);
            isData = false;
        }

        /**
         * 构建器
         * @return
         */
        public static JavaStringBuilder builder() {
            return new JavaStringBuilder();
        }

        /**
         * 添加包名
         * @param pkg
         * @return
         */
        public JavaStringBuilder pack(Package pkg) {
            pack.append(pkg.toString()).endWithNewline();
            return this;
        }

        /**
         * 多个类注解
         * @param annotations
         * @return
         */
        public JavaStringBuilder annotations(List<Annotation> annotations) {
            if (CollectionUtils.isEmpty(annotations)) {
                return this;
            }

            for (Annotation annotation : annotations) {
                if (annotation == null) {
                    continue;
                }

                if (annotation.equals(Annotation.DATA)) {
                    isData = true;
                }

                this.annotations.append(annotation.toString()).newLine();
            }
            return this;
        }

        /**
         * 添加一个注解
         * @param annotation
         * @return
         */
        public JavaStringBuilder annotation(Annotation annotation) {
            if (annotation != null) {
                this.annotations.append(annotation.toString()).endWithNewline();
            }
            return this;
        }

        /**
         * 添加 import
         * @param imports
         * @return
         * @param <T>
         */
        public <T extends Import> JavaStringBuilder imports(List<T> imports) {
            if (imports == null) {
                return this;
            }

            for (Import imp : imports) {
                this.imports.append(imp.getImport()).endWithNewline();
            }
            return this;
        }

        /**
         * 设置扩展类
         * @param extend
         */
        private void setExtend(Extend extend) {

            if (extend == null) {
                return;
            }

            this.entity.appendWithSpace(EXTENDS);

            this.entity.append(extend.getName());

            if (this.isData) {
                annotation(Annotation.EQUALS_AND_HASHCODE);
            }
        }

        /**
         * 字段是否在扩展类中
         * @param extend
         * @param field
         * @return
         */
        private boolean isInExtends(Extend extend, Field field) {
            if (extend == null) {
                return false;
            }
            return extend.contains(field.getName());
        }

        /**
         * 添加字段
         * @param fields
         * @param extend
         */
        private void addFields(List<Field> fields,
                               Extend extend) {
            for (Field field : fields) {
                if (isInExtends(extend, field)) {
                    continue;
                }
                this.entity.appendWithPrefixTab(field.toPrivate())
                        .endWithNewline();
            }
        }

        /**
         * 添加 getters 和 setters
         * @param fields
         */
        private void addGettersAndSetters(List<Field> fields) {
            for (Field field : fields) {
                this.entity.appendWithNewline(field.toGetter());
                this.entity.newLine();
                this.entity.appendWithNewline(field.toSetter());
                this.entity.newLine();
            }
            this.entity.deleteLastChar();
        }

        /**
         * 添加实体字段
         * @param entity
         * @param extendList
         * @return
         */
        public JavaStringBuilder entity(Entity entity, Extend extend) {
            this.entity.appendWithSpace(START_PREFIX)
                    .appendWithSpace(entity.getName());

            setExtend(extend);

            this.entity.appendWithNewline(BRACE_START);

            addFields(entity.getFields(), extend);

            if (!isData) {
                this.entity.newLine();
                addGettersAndSetters(entity.getFields());
            }

            this.entity.appendWithNewline(BRACE_END);

            return this;
        }

        /**
         * 格式化
         * @param pack
         * @param entity
         * @return
         */
        public JavaFormat format(Package pack, Entity entity) {
            return new JavaFormat(pack.toFilePath(),
                    this.pack.toString(),
                    imports.toString(),
                    annotations.toString(),
                    entity.getName(),
                    this.entity.toString());
        }

        @Override
        public String toString() {
            return pack + "\n" +
                    imports + "\n" +
                    annotations +
                    entity;
        }
    }

    private final Package packagePath;
    private final List<Annotation> annotations;
    private final Extend extend;

    public JavaFormatProcessor(Package packagePath, List<Annotation> annotations, Extend extend) {
        this.packagePath = packagePath;
        this.annotations = annotations;
        this.extend = extend;
    }

    private String doString(Entity entity) throws JavaFormatException {
        if (entity == null) {
            throw new JavaFormatException("entity is null");
        }

        return JavaStringBuilder.builder()
                .pack(packagePath)
                .annotations(annotations)
                .imports(annotations)
                .imports(List.of(extend))
                .entity(entity, extend)
                .toString();
    }

    public List<String> strings(List<Entity> entities) throws JavaFormatException {
        if (packagePath == null || packagePath.isEmpty()) {
            throw new JavaFormatException("Package path is isEmpty");
        }

        List<String> res = new ArrayList<>();
        for (Entity entity : entities) {
            res.add(doString(entity));
        }
        return res;
    }

    private JavaFormat doFormat(Entity entity) throws JavaFormatException {
        if (entity == null) {
            throw new JavaFormatException("entity is null");
        }

        return JavaStringBuilder.builder()
                .pack(packagePath)
                .annotations(annotations)
                .imports(annotations)
                .imports(List.of(extend))
                .entity(entity, extend)
                .format(packagePath, entity);
    }

    public List<JavaFormat> formats(List<Entity> entities) throws JavaFormatException {
        if (packagePath == null || packagePath.isEmpty()) {
            throw new JavaFormatException("Package path is isEmpty");
        }

        List<JavaFormat> res = new ArrayList<>();
        for (Entity entity : entities) {
            res.add(doFormat(entity));
        }
        return res;
    }
}
